/* DisplayCalculationOutput.cs - View
 * Copyright (C) 2009 Dietmar Schinnerl
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

using System.Collections;
using System.Windows.Forms;
using System.Drawing;
using System;

namespace App.Net
{
    public sealed class DisplayCalculationOutput
    {
        private DisplayCalculationOutput() { }

        public static void BestResultStatsRichText(Calculation calculation, RichTextBox richTextBox, bool shortStatsOnly)
        {
            if ((calculation != null) && (calculation.BestError != Calculation.BestErrorStartValue))
            {
                richTextBox.Clear();


                Font labelFont = new Font("Arial", 10, FontStyle.Underline);

                #region TASKS


                if (shortStatsOnly == false)
                {
                    richTextBox.SelectionFont = labelFont;
                    richTextBox.AppendText("Tasks:\n");
                }

                var sortedCalcTaskList = calculation.TaskList;
                //sortedCalcTaskList.Sort();

                foreach (CalcTask calcTask in sortedCalcTaskList)
                {
                    if (calcTask.BestError == 0)
                        richTextBox.SelectionColor = Color.Black;
                    else
                        richTextBox.SelectionColor = Color.Red;
                    richTextBox.AppendText(calcTask.Task.Name + ": " + calcTask.Task.EarliestStartDate.DateTime.ToShortDateString() + " - " + calculation.BestResult.TaskEndDate(calcTask.Task).ToShortDateString() + " (" + calcTask.Task.ExpectedEndDate.DateTime.ToShortDateString() + ", e" + calcTask.BestError.ToString() + ", p" + calcTask.Priority.ToString() + ")\n");
                }
                #endregion



                if (shortStatsOnly == false)
                {
                    richTextBox.AppendText("\n\n");

                    #region PHASES
                    richTextBox.SelectionFont = labelFont;
                    richTextBox.AppendText("Phases:\n");

                    int p = 1;
                    foreach (PhaseMetadata pmd in calculation.BestResult.PhaseMdList)
                    {
                        richTextBox.AppendText("Phase " + p++.ToString() + ": " + pmd.StartDate.ToShortDateString() + " - " + pmd.EndDate.ToShortDateString() + "\n");
                        foreach (Task t in pmd.TasksFinished)
                        {
                            richTextBox.AppendText("   " + t.Name + "\n");
                        }
                    }
                    #endregion
                    richTextBox.AppendText("\n\n");

                    #region WORKERS / PHASES
                    richTextBox.SelectionFont = labelFont;
                    richTextBox.AppendText("Workers / Phases:\n");



                    richTextBox.AcceptsTab = true;
                    richTextBox.SelectionTabs = new int[1] { 200 };

                    for (int workerIndex = 0; workerIndex < calculation.WorkerList.Count; workerIndex++)
                    {
                        richTextBox.AppendText(((CalcWorker)calculation.WorkerList[workerIndex]).Worker.Name + ":\n");



                        for (int taskIndex = 0; taskIndex < calculation.TaskList.Count; taskIndex++)
                        {
                            richTextBox.AppendText("   " + ((CalcTask)calculation.TaskList[taskIndex]).Task.Name + ":\t");
                            for (int phase = 0; phase < calculation.BestResult.Phases; phase++)
                            {
                                richTextBox.AppendText(calculation.BestResult.PhaseAssignment[workerIndex, taskIndex, phase].ToString() + "\t");
                            }
                            richTextBox.AppendText("\n");
                        }

                    }

                    #endregion

                    richTextBox.AppendText("\n\n");

                    #region WORKERS / WEEKS

                    richTextBox.SelectionFont = labelFont;
                    richTextBox.AppendText("Workers / Weeks:\n");

                    for (int workerIndex = 0; workerIndex < calculation.WorkerList.Count; workerIndex++)
                    {
                        richTextBox.AppendText(((CalcWorker)calculation.WorkerList[workerIndex]).Worker.Name + ":\n");

                        richTextBox.AppendText("   Weekly Working Hours:\n      ");
                        for (int week = 0; week < 45; week++)
                        {
                            richTextBox.AppendText(calculation.BestResult.WeeklyAssignment[workerIndex, calculation.TaskList.Count, week].ToString("00") + " ");
                        }
                        richTextBox.AppendText("\n");


                        for (int taskIndex = 0; taskIndex < calculation.TaskList.Count; taskIndex++)
                        {
                            richTextBox.AppendText("   " + ((CalcTask)calculation.TaskList[taskIndex]).Task.Name + ":\n      ");
                            for (int week = 0; week < 45; week++)
                            {
                                richTextBox.AppendText(calculation.WeeklyAssignment[workerIndex, taskIndex, week].ToString("00") + " ");
                            }
                            richTextBox.AppendText("\n");
                        }
                    }
                    #endregion
                }

                richTextBox.SelectionStart = 0;
                richTextBox.SelectionLength = 0;
            }
        }
        /// 
        /// <param name="calculation"></param>
        /// <param name="graphics"></param>
        /// <param name="pictureBox"></param>
        public static void BestResultDefaultGraphics(Calculation calculation, Graphics graphics, Control pictureBox)
        {

            graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;

            if ((calculation != null) && (calculation.BestError != Calculation.BestErrorStartValue))
            {
                int yOffset = 30;
                int xOffset = 30;
                int yOrigin = pictureBox.Height;
                int height = pictureBox.Height - 2 * yOffset;
                int width = pictureBox.Width - 2 * xOffset;
                float weekX = (float)width / (calculation.BestResult.LastWeekWorking + 1);

                #region calculate thickness of pens
                float thickness = 0.5F;
                thickness += weekX * 0.05F;

                if (calculation.TaskList.Count <= 10)
                    thickness += (10 - calculation.TaskList.Count) * 0.15F;
                FontStyle fontStyle = FontStyle.Regular;
                if (thickness >= 2.0)
                    fontStyle = FontStyle.Bold;
                if (thickness > 5)
                    thickness = 5;
                #endregion


                #region find longest task for Y scaling
                int longestY = 0;
                foreach (CalcTask calcTask in calculation.TaskList)
                {
                    if (calcTask.Task.EstimatedHours > longestY)
                        longestY = calcTask.Task.EstimatedHours;
                }
                #endregion
                float hoursY = (float)height / longestY;

                #region PAINT

                int fontSize = 10;
                if (height / 20 < 10) fontSize = height / 20;

                Font myFont = new Font("Arial", fontSize, fontStyle);
                Pen gridPen = new Pen(Color.Gray, thickness);

                #region PAINT GRID

                #region X
                int dayMultiplier = 1;
                if (calculation.AppProject.CalculationPeriod == AppProject.Period.Weekly)
                    dayMultiplier = 7;

                DateTime thisDT = calculation.AppProject.StartDate.DateTime;

                for (int day = 0; day <= calculation.BestResult.LastWeekWorking * dayMultiplier; day++)
                {
                    thisDT = calculation.AppProject.StartDate.DateTime.AddDays(day);
                    if (thisDT.DayOfWeek == DayOfWeek.Monday)
                    {
                        int kalenderWochePos = (((thisDT - calculation.AppProject.StartDate.DateTime).Days) / 7) + 1;
                        string thisMondayString = kalenderWochePos.ToString();
                        if (kalenderWochePos % 2 == 0)
                            graphics.FillRectangle(Brushes.Beige, xOffset + ((kalenderWochePos - 1) * (8 - dayMultiplier) * weekX), 0, (8 - dayMultiplier) * weekX, pictureBox.Height + 0);

                    }
                }

                graphics.DrawLine(gridPen, 0, yOrigin - yOffset, pictureBox.Width, yOrigin - yOffset);

                float lastPosEnd = 0;
                for (int day = 0; day <= calculation.BestResult.LastWeekWorking * dayMultiplier; day++)
                {
                    thisDT = calculation.AppProject.StartDate.DateTime.AddDays(day);
                    if (thisDT.DayOfWeek == DayOfWeek.Monday)
                    {

                        int kalenderWochePos = (((thisDT - calculation.AppProject.StartDate.DateTime).Days) / 7) + 1;
                        int kalenderWoche = ((thisDT.AddDays(5).DayOfYear / 7) + 1);
                        string thisMondayString = kalenderWoche.ToString();
                        float pos = 5 + xOffset + ((kalenderWochePos - 1) * (8 - dayMultiplier) * weekX);
                        if (pos > lastPosEnd)
                        {
                            graphics.DrawString(thisMondayString, myFont, Brushes.Black, pos, yOrigin - yOffset + 5);
                            float stringSize = graphics.MeasureString(thisMondayString, myFont).Width + fontSize;
                            lastPosEnd = pos + stringSize;
                        }

                    }


                }
                #endregion

                #region Y
                graphics.DrawLine(gridPen, xOffset, yOrigin, xOffset, 0);
                #endregion
                #endregion

                #region PAINT TASKS
                for (int calcTaskIndex = 0; calcTaskIndex < calculation.TaskList.Count; calcTaskIndex++)
                {
                    CalcTask calcTask = (CalcTask)calculation.TaskList[calcTaskIndex];
                    int sumHoursPerTask = calcTask.Task.EstimatedHours - calcTask.Task.RemainingHours;
                    for (int week = 0; week <= calculation.BestResult.LastWeekWorking; week++)
                    {
                        int hoursPerTask = 0;
                        for (int calcWorkerIndex = 0; calcWorkerIndex < calculation.WorkerList.Count; calcWorkerIndex++)
                        {
                            hoursPerTask += calculation.BestResult.WeeklyAssignment[calcWorkerIndex, calcTaskIndex, week];
                        }
                        if (sumHoursPerTask + hoursPerTask > calcTask.Task.EstimatedHours)
                            hoursPerTask = calcTask.Task.EstimatedHours - sumHoursPerTask;

                        if ((sumHoursPerTask == 0) && (hoursPerTask == 0))
                            continue;
                        if (sumHoursPerTask >= calcTask.Task.EstimatedHours)
                            continue;
                        Pen myPen = new Pen(Color.FromArgb(calcTask.Task.Argb), thickness);
                        graphics.DrawLine(myPen, xOffset + week * weekX, yOrigin - yOffset - (sumHoursPerTask * hoursY), xOffset + ((week + 1) * weekX), yOrigin - yOffset - ((sumHoursPerTask + hoursPerTask) * hoursY));

                        sumHoursPerTask += hoursPerTask;


                    }
                }
                #endregion

                #region PAINT PHASES

                for (int phase = 0; phase < calculation.BestResult.Phases; phase++)
                {
                    PhaseMetadata pmd = (PhaseMetadata)calculation.BestResult.PhaseMdList[phase];

                    int phaseXpos = (int)(xOffset + (pmd.EndWeek * weekX));
                    // Line                    
                    graphics.DrawLine(gridPen, phaseXpos, yOrigin, phaseXpos, 0);

                    // Date of Phase 
                    String phaseStr = pmd.EndDate.ToShortDateString();
                    graphics.DrawString(phaseStr, myFont, Brushes.Black, phaseXpos - 1, 10, new StringFormat(StringFormatFlags.DirectionVertical));
                    int lastStringSize = (int)graphics.MeasureString(phaseStr, myFont).Width + fontSize * 2;

                    // All tasks of that phase in their color

                    foreach (Task task in pmd.TasksFinished)
                    {
                        graphics.DrawString(task.Name, myFont, new SolidBrush(Color.FromArgb(task.Argb)), phaseXpos - 1, lastStringSize, new StringFormat(StringFormatFlags.DirectionVertical));
                        lastStringSize += (int)graphics.MeasureString(task.Name, myFont).Width + fontSize;

                    }

                }

                #endregion

                #endregion
            }


        }





    }//end DisplayCalculationOutput


}